import os

from flasgger import Swagger
from flask import Flask, jsonify, request, send_from_directory
from flask_mail import Mail
from sqlalchemy import inspect

from config.config import Config
from models.models import db
from routes.auth import auth_bp
from routes.chat import chat_bp
from routes.detection import detection_bp
from routes.device import device_bp
from routes.gps import gps_bp
from routes.sensor import sensor_bp
from services.auth_service import VerificationCodeManager, EmailService
from services.yolo_service import YOLOService

# 创建Flask应用，配置静态文件路径
app = Flask(__name__, 
           static_folder='static',     # 静态文件目录
           static_url_path='/static')  # 静态文件URL路径

# 加载配置
app.config.from_object(Config)
Config.init_app(app)

# 初始化扩展
db.init_app(app)
mail = Mail(app)

# 初始化服务
code_manager = VerificationCodeManager()
email_service = EmailService(app, mail)
yolo_service = YOLOService()

# 将服务实例添加到app对象中，以便蓝图可以访问
app.code_manager = code_manager
app.email_service = email_service
app.yolo_service = yolo_service

# 注册蓝图
app.register_blueprint(auth_bp, url_prefix='/api/auth')
app.register_blueprint(sensor_bp, url_prefix='/api/sensor')
app.register_blueprint(device_bp, url_prefix='/api/devices')
app.register_blueprint(gps_bp, url_prefix='/api/gps')
app.register_blueprint(detection_bp, url_prefix='/api/detect')
app.register_blueprint(chat_bp, url_prefix='/api/chat')

# 添加直接访问uploads目录内文件的路由
@app.route('/uploads/<path:filename>')
def uploaded_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

@app.route('/avatars/<path:filename>')
def avatar_file(filename):
    return send_from_directory(app.config['AVATAR_FOLDER'], filename)

@app.route('/devices/<path:filename>')
def device_file(filename):
    return send_from_directory(app.config['DEVICE_FOLDER'], filename)

# 在应用初始化后添加
swagger_config = {
    "headers": [],
    "specs": [
        {
            "endpoint": 'apispec',
            "route": '/apispec.json',
            "rule_filter": lambda rule: True,  # 所有端点
            "model_filter": lambda tag: True,  # 所有模型
        }
    ],
    "static_url_path": "/flasgger_static",
    "swagger_ui": True,
    "specs_route": "/swagger/"
}

swagger = Swagger(app, 
    template={
        "info": {
            "title": "物联网设备管理API",
            "description": "提供设备管理、传感器数据收集和目标检测的API",
            "version": "1.0.0",
            "termsOfService": ""
        },
        "schemes": ["http", "https"],
    },
    config=swagger_config
)

# 添加请求日志中间件
@app.after_request
def log_request(response):
    app.logger.info(
        f"{request.remote_addr} {request.method} {request.path} {response.status_code}"
    )
    return response

@app.errorhandler(404)
def not_found(error):
    return jsonify({"error": "资源未找到"}), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({"error": "服务器内部错误"}), 500

def validate_database():
    inspector = inspect(db.engine)
    # 从SQL文件获取的准确表清单
    required_tables = {
        'users', 'devices', 'sensor_data',
        'gps_data', 'object_detection'
    }
    existing_tables = set(inspector.get_table_names())
    # 验证缺失表
    missing_tables = required_tables - existing_tables
    if missing_tables:
        raise RuntimeError(f"数据库缺失表: {', '.join(missing_tables)}")
    # 验证object_detection表结构
    obj_detect_columns = {
        'id', 'image_path', 'result_path',
        'object_count', 'detection_data', 'timestamp'
    }
    actual_columns = set(col['name'] for col in inspector.get_columns('object_detection'))
    if obj_detect_columns != actual_columns:
        raise RuntimeError("目标检测表结构不匹配")

app.config['DEBUG'] = True

if __name__ == '__main__':
    with app.app_context():
        # 仅创建不存在的表
        db.create_all()
        # 验证数据库结构
        try:
            validate_database()
        except RuntimeError as e:
            print(f"数据库验证失败: {str(e)}")
            exit(1)
        # 在保存图片前添加
        print("当前工作目录:", os.getcwd())
        print("结果目录绝对路径:", os.path.abspath(app.config['RESULT_FOLDER']))
        # 尝试手动创建测试文件
        test_file = os.path.join(app.config['RESULT_FOLDER'], 'test.txt')
        with open(test_file, 'w') as f:
            f.write("test")
        # 添加端口释放逻辑
        app.run(host='0.0.0.0', port=6000, threaded=True,
                extra_files=[__file__]
                )
